非局部变量的初始化

  原则上说,在所有函数之外定义的变量(即那些全局的、名字空间的和类的static变量)应该在main()的调用之前完成初始化。在一个编译单位内的这种非局部变量将按照它们的定义顺序进行初始化(10.4.9节)。如果某个这样的变量没有显式的初始式,它将被初始化为有关类型的默认值(10.4.2节)。对于内部类型和枚举,默认的初始值是0。例如,

    double x = 2;                // 非局部变量
    double y;
    double sqx = sqrt(x + y);

在这里,x和y都在sqx之前初始化,所以调用的是sqrt(2)。

  对于不同编译单位里的全局变量,其初始化的顺序则没有任何保证。因此,对于不同编译单位里的全局变量,在它们的初始式之间建立任何顺序依赖都是很不明智的。此外,也没有办法捕捉由全局变量的初始化抛出的异常(14.7节)。一般来说,最好是尽量减少全局变量的使用,特别是限制使用那些要求复杂初始化的全局变量。

  也存在着一些技术,可以用于给全局变量的初始化之间强加上某些顺序性。但是,没有一种技术是既可移植又有效的。特别地,动态连接库与具有复杂依赖关系的全局变量也无法很好地共存。

  通过函数返回的引用可以作为全局变量的一种很好的替代物。例如,

    int& use_cout()
    {
        static int uc = 0;
        return uc;
    }

对use_count()的调用在行为上就像是一个全局变量,除了它是在第一次使用时才被初始化之外(5.5节、7.1.2节)。例如,

    void f()
    {
        cout << ++use_coutn();            // 读和增加
        // ...
    }

非局部静态变量的初始化由具体实现中启动C++程序所用的机制控制,只有main()被执行,这一机制才保证能正确工作。因此,如果要将一段C++代码作为某个非C++程序的一部分去执行,我们就应该避免在其中定义需要运行中初始化的非局部变量。

  请注意,通过常量表达式(C.5节)初始化的变量不会依赖于来自其他编译单位的对象,因此不需要在运行时初始化。这种变量可以安全地用于所有情况。

🔚